package repository

import (
	"oa-system/internal/model"
	"oa-system/pkg/errors"

	"gorm.io/gorm"
)

// UserRepository 用户仓库接口
type UserRepository interface {
	GetAllUsersWithRoles(page, pageSize int, departmentID *uint, email, name string, roleIDs []uint) (users []model.User, total int64, err error)
	CreateUser(user *model.User, roleIDs []uint) (*model.User, error)
	UpdateUser(user *model.User, roleIDs []uint) (*model.User, error)
	DeleteUser(id uint) error
	ExistsByEmail(email string) (bool, error)
	ExistsByEmailExcept(email string, exceptID uint) (bool, error) // 邮箱正则
	ExistsByPhone(phone string) (bool, error)
	ExistsByPhoneExcept(phone string, exceptID uint) (bool, error) // 手机号正则
	GetUserByID(id uint) (*model.User, error)
	GetUserByEmail(email string) (*model.User, error)
}

// userRepository 实现 UserRepository 接口
type userRepository struct {
	db *gorm.DB
}

// NewUserRepository 创建用户仓库实例
func NewUserRepository(db *gorm.DB) UserRepository {
	return &userRepository{db: db}
}

// GetAllUsersWithRoles 获取用户列表，支持分页、部门过滤、角色过滤和搜索
func (r *userRepository) GetAllUsersWithRoles(page, pageSize int, departmentID *uint, email, name string, roleIDs []uint) ([]model.User, int64, error) {
	var users []model.User
	var total int64

	// 构建基础查询
	query := r.buildBaseQuery()

	// 应用过滤条件
	query = r.applyFilters(query, departmentID, email, name, roleIDs)

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, errors.Wrap(err, "count users failed")
	}

	// 应用分页并获取数据
	if err := r.applyPaginationAndGet(query, page, pageSize, &users); err != nil {
		return nil, 0, err
	}

	return users, total, nil
}

// buildBaseQuery 构建基础查询
func (r *userRepository) buildBaseQuery() *gorm.DB {
	return r.db.Model(&model.User{}).
		Preload("Roles").
		Preload("Department")
}

// applyFilters 应用过滤条件
func (r *userRepository) applyFilters(query *gorm.DB, departmentID *uint, email, name string, roleIDs []uint) *gorm.DB {
	// 部门过滤
	if departmentID != nil {
		departmentIDs, err := r.getAllDepartmentIDs(*departmentID)
		if err != nil {
			// 如果获取部门ID失败，仅使用当前部门ID
			query = query.Where("department_id = ?", departmentID)
		} else {
			query = query.Where("department_id IN ?", departmentIDs)
		}
	}

	// 邮箱搜索
	if email != "" {
		query = query.Where("email LIKE ?", "%"+email+"%")
	}

	// 名称搜索
	if name != "" {
		query = query.Where("name LIKE ?", "%"+name+"%")
	}

	// 角色过滤
	if len(roleIDs) > 0 {
		query = query.Distinct().
			Joins("JOIN user_roles ON user_roles.user_id = users.id").
			Where("user_roles.role_id IN ?", roleIDs)
	}

	return query
}

// applyPaginationAndGet 应用分页并获取数据
func (r *userRepository) applyPaginationAndGet(query *gorm.DB, page, pageSize int, users *[]model.User) error {
	err := query.
		Offset((page - 1) * pageSize).
		Limit(pageSize).
		Find(users).Error

	if err != nil {
		return errors.Wrap(err, "fetch users failed")
	}

	return nil
}

// getAllDepartmentIDs 获取部门及其子部门的ID列表
func (r *userRepository) getAllDepartmentIDs(departmentID uint) ([]uint, error) {
	var departments []model.Department

	// 获取所有部门
	if err := r.db.Find(&departments).Error; err != nil {
		return nil, errors.Wrap(err, "fetch departments failed")
	}

	// 构建部门树
	departmentMap := make(map[uint][]model.Department)
	for _, dept := range departments {
		parentID := uint(0)
		if dept.ParentID != nil {
			parentID = *dept.ParentID
		}
		departmentMap[parentID] = append(departmentMap[parentID], dept)
	}

	// 收集部门ID
	var departmentIDs []uint
	var collectDepartmentIDs func(id uint)
	collectDepartmentIDs = func(id uint) {
		departmentIDs = append(departmentIDs, id)
		for _, child := range departmentMap[id] {
			collectDepartmentIDs(child.ID)
		}
	}

	collectDepartmentIDs(departmentID)
	return departmentIDs, nil
}

func (r *userRepository) CreateUser(user *model.User, roleIDs []uint) (*model.User, error) {
	return user, r.db.Transaction(func(tx *gorm.DB) error {
		// 创建用户
		if err := tx.Create(user).Error; err != nil {
			return err
		}

		// 创建用户角色关联
		for _, roleID := range roleIDs {
			if err := tx.Create(&model.UserRole{
				UserID: user.ID,
				RoleID: roleID,
			}).Error; err != nil {
				return err
			}
		}

		// 重新加载用户信息，包括角色
		return tx.Preload("Roles").First(user, user.ID).Error
	})
}

func (r *userRepository) UpdateUser(user *model.User, roleIDs []uint) (*model.User, error) {
	return user, r.db.Transaction(func(tx *gorm.DB) error {
		// 更新用户基本信息
		if err := tx.Model(user).Omit("created_at").Updates(user).Error; err != nil {
			return err
		}

		// 删除旧的角色关联
		if err := tx.Where("user_id = ?", user.ID).Delete(&model.UserRole{}).Error; err != nil {
			return err
		}

		// 创建新的角色关联
		for _, roleID := range roleIDs {
			if err := tx.Create(&model.UserRole{
				UserID: user.ID,
				RoleID: roleID,
			}).Error; err != nil {
				return err
			}
		}

		// 重新加载用户信息，包括角色
		return tx.Preload("Roles").First(user, user.ID).Error
	})
}

// DeleteUser 删除用户
func (r *userRepository) DeleteUser(id uint) error {
	// 开启事务
	return r.db.Transaction(func(tx *gorm.DB) error {
		// 先删除用户角色关联
		if err := tx.Where("user_id = ?", id).Delete(&model.UserRole{}).Error; err != nil {
			return err
		}

		// 再删除用户
		if err := tx.Delete(&model.User{}, id).Error; err != nil {
			return err
		}

		return nil
	})
}

// ExistsByEmail 检查邮箱是否存在
func (r *userRepository) ExistsByEmail(email string) (bool, error) {
	var count int64
	if err := r.db.Model(&model.User{}).Where("email = ?", email).Count(&count).Error; err != nil {
		return false, errors.Wrap(err, "count users failed")
	}
	return count > 0, nil
}

// ExistsByEmailExcept 检查邮箱是否存在，排除指定用户ID
func (r *userRepository) ExistsByEmailExcept(email string, exceptID uint) (bool, error) {
	var count int64
	if err := r.db.Model(&model.User{}).Where("email = ? AND id != ?", email, exceptID).Count(&count).Error; err != nil {
		return false, errors.Wrap(err, "count users failed")
	}
	return count > 0, nil
}

// ExistsByPhone 检查手机号是否存在
func (r *userRepository) ExistsByPhone(phone string) (bool, error) {
	var count int64
	if err := r.db.Model(&model.User{}).Where("phone = ?", phone).Count(&count).Error; err != nil {
		return false, errors.Wrap(err, "count users failed")
	}
	return count > 0, nil
}

// ExistsByPhoneExcept 检查手机号是否存在，排除指定用户ID
func (r *userRepository) ExistsByPhoneExcept(phone string, exceptID uint) (bool, error) {
	var count int64
	if err := r.db.Model(&model.User{}).Where("phone = ? AND id != ?", phone, exceptID).Count(&count).Error; err != nil {
		return false, errors.Wrap(err, "count users failed")
	}
	return count > 0, nil
}

// GetUserByID 根据ID获取用户
func (r *userRepository) GetUserByID(id uint) (*model.User, error) {
	var user model.User
	if err := r.db.First(&user, id).Error; err != nil {
		return nil, err
	}
	return &user, nil
}

// GetUserByEmail 根据邮箱获取用户
func (r *userRepository) GetUserByEmail(email string) (*model.User, error) {
	var user model.User
	if err := r.db.Where("email = ?", email).First(&user).Error; err != nil {
		return nil, err
	}
	return &user, nil
}
